//-----------------------------------------------------------------------------
//
// CodeXS - Copyright(c) Businessware Architects cc
// Contact: Willem J Fourie
// E-mail : willemf@bware.biz
//
// This file is part of CodeXS.
//
// CodeXS is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License (GPL) as 
// published by the Free Software Foundation version 2 of the License.
//
//
// CodeXS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with CodeXS; if not, write to:
//
// Free Software Foundation, Inc.
// 59 Temple Place
// Suite 330
// Boston
// MA  02111-1307  USA
//
//-----------------------------------------------------------------------------

using System;
using System.Collections;
using System.Reflection;
using System.Diagnostics;
using System.Text;
using System.IO;

namespace CodeXS.Diagnostics
{
	public class Log
	{
		private static string logEntryPrefixFormat = 
			"yyyy/MM/dd HH:mm:ss : ";
		public static string LogEntryPrefixFormat
		{
			get
			{
				return System.DateTime.Now.
					ToString(logEntryPrefixFormat);
			}
		}
		private static Log defaultLog = null;
		public static Log DefaultLog
		{
			get
			{
				return defaultLog;
			}
			set
			{
				defaultLog = value;
			}
		}
		public enum LogDestination
		{
			None, Debug, EventLog, LogFile
		}
		public string FormatMessage(string message)
		{
			message = message.Replace(LineTerminator, LineTerminator + LineIndent);
			if(message.EndsWith(LineIndent))
			{
				message = message.Substring(0, message.Length - LineIndent.Length);
			}
			if( ! message.EndsWith(LineTerminator))
			{
				message += LineTerminator;
			}
			message = LogEntryPrefixFormat + message;
			return message;
		}
		private void LogMessage(LogDestination logDestination, string message)
		{
			message = FormatMessage(message);
			// CHANGE: 2006-06-19:	  Version 0.56 Beta
			// Add following lines for debugging purposes:
#if DEBUG
			// Uncomment the following if you want debug tracing..
			if (logDestination != LogDestination.Debug)
			{
				Debug.Write(message);
			}
#endif // DEBUG
			switch (logDestination)
			{
				case LogDestination.Debug:
					Debug.Write(message);
					break;
				case LogDestination.EventLog:
					throw new InvalidOperationException("Logging not implemented");
				case LogDestination.LogFile:
					FileInfo logFileInfo = new FileInfo(LogFilePath);
					if( ! logFileInfo.Directory.Exists)
					{
						logFileInfo.Directory.Create();
					}
					if( ! logFileInfo.Exists)
					{
						FileStream fs = logFileInfo.Create();
						fs.Close();
					}
					using (StreamWriter sw = new StreamWriter(LogFilePath, true, Encoding.ASCII))
					{
						sw.Write(message);
						sw.Flush();
						sw.Close();
					}
					break;
				case LogDestination.None:
				default:
					break;
			}
		}
		public Log(LogDestination Destination)
		{
			destination = Destination;
		}
		public void LogMessage(string format, params object[] args)
		{
			LogMessage(Destination, string.Format(format, args));
		}
		public void LogMessage(string message)
		{
			LogMessage(Destination, message);
		}
		public void LogMessageLine(string format, params object[] args)
		{
			LogMessage(Destination, string.Format(format, args) + LineTerminator);
		}
		public void LogMessageLine(string message)
		{
			LogMessage(message + LineTerminator);
		}
		public void LogMessage(string[] messageContent)
		{
			StringBuilder builder = new StringBuilder();
			foreach(string messageLine in messageContent)
			{
				BuildMessage(builder, messageLine);
			}
			LogMessage(builder.ToString());
		}
		private string _logExceptionHeader = "****** BEGIN --- Exception Report ******";
		private string _logExceptionFooter = "******  END  --- Exception Report ******";
		public void LogException(Exception ex)
		{
			ArrayList contentList = new ArrayList();
			contentList.Add("Exception:");
			contentList.Add("------ Stack trace:");
			StackTrace trace = new StackTrace(ex, true);
			for(int frameIndex = 0; frameIndex < trace.FrameCount; frameIndex++)
			{
				StringBuilder builder = new StringBuilder();
				StackFrame frame = trace.GetFrame(frameIndex);
				string fileName = frame.GetFileName();
				if (fileName == null)
				{
					builder.Append("<unknown file>");
				}
				else
				{
					builder.Append(fileName);
					builder.Append("(");
					builder.Append(frame.GetFileLineNumber().ToString());
					builder.Append(",");
					builder.Append(frame.GetFileColumnNumber().ToString());
					builder.Append("): ");
				}
				MethodBase method = frame.GetMethod();
				builder.Append("{");
				Uri uri = new Uri(method.DeclaringType.Assembly.GetName().EscapedCodeBase);
				FileInfo assemblyFileInfo = new FileInfo(uri.LocalPath);
				builder.Append(assemblyFileInfo.Name);
				builder.Append("} ");
				builder.Append(method.ReflectedType.FullName);
				builder.Append("." + method.Name);
				contentList.Add(builder.ToString());
			}
			contentList.Add("------ Exception trace:");
			contentList.Add(_logExceptionHeader);
			do
			{
				contentList.Add(ex.Message);
			}
			while ((ex = ex.InnerException) != null);
			contentList.Add(_logExceptionFooter);
			contentList.Add(LineTerminator);
			LogMessage((string[])contentList.ToArray(typeof(string)));
		}
		private LogDestination destination = LogDestination.None;
		public LogDestination Destination
		{
			get
			{
				return destination;
			}
		}
		private string logFilePath = "CodeXS.log";
		public string LogFilePath
		{
			get
			{
				return logFilePath;
			}
			set
			{
				logFilePath = value;
			}
		}
		public void Delete()
		{
			switch(this.Destination)
			{
				case LogDestination.LogFile:
					FileInfo fileInfo = new FileInfo(this.LogFilePath);
					if(fileInfo.Exists)
					{
						fileInfo.Delete();
					}
					break;
				case LogDestination.Debug:
				case LogDestination.EventLog:
				default:
					break;
			}
		}
		private static string lineTerminator = "\r\n";
		public static string LineTerminator
		{
			get
			{
				return lineTerminator;
			}
			set
			{
				lineTerminator = value;
			}
		}
		private static string lineIndent = "  ";
		public static string LineIndent
		{
			get
			{
				return lineIndent;
			}
			set
			{
				lineIndent = value;
			}
		}
		public static StringBuilder BuildMessage(StringBuilder builder, 
			string messageLine)
		{
			if(builder.ToString() != string.Empty)
			{
				builder.Append(LineTerminator);
			}
			builder.Append(messageLine);
			return builder;
		}
		public static StringBuilder BuildMessage(StringBuilder builder, 
			string[] message)
		{
			foreach(string messageLine in message)
			{
				BuildMessage(builder, messageLine);
			}
			return builder;
		}
	}
}
